package com.ideal.manage.esms.service.diagnostic;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ideal.manage.esms.bean.diagnostic.DiagnoseResultBatch;
import com.ideal.manage.esms.bean.diagnostic.DiagnoseResultInfo;
import com.ideal.manage.esms.bean.diagnostic.QDiagnoseResultBatch;
import com.ideal.manage.esms.bean.diagnostic.QDiagnoseResultInfo;
import com.ideal.manage.esms.bean.esms.EsmsDataBatch;
import com.ideal.manage.esms.bean.esms.QEsmsDataBatch;
import com.ideal.manage.esms.bean.project.*;
import com.ideal.manage.esms.jpa.JpaRepositoryImpl;
import com.ideal.manage.esms.service.ElasticsearchService;
import com.ideal.manage.esms.service.MatchFunction;
import com.querydsl.core.types.dsl.BooleanExpression;
import org.elasticsearch.index.query.QueryBuilders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import java.util.*;

@Service
@Transactional
public class DiagnoseApiService {
    private Logger LOG = LoggerFactory.getLogger(DiagnoseApiService.class);

    @Autowired
    private EntityManager entityManager;
    @Autowired
    private ElasticsearchService elasticsearchService;

    private JpaRepositoryImpl<ParameterInfo, String> parameterJpaRepository;
    private JpaRepositoryImpl<EquipmentManage, String> equipmentManageJpaRepository;
    private JpaRepositoryImpl<DiagnoseResultInfo, String> diagnoseResultInfoJpaRepository;
    private JpaRepositoryImpl<DiagnoseResultBatch, Long> diagnoseBatchJpaRepository;
    private JpaRepositoryImpl<EsmsDataBatch, Long> dataBatchJpaRepository;

    @PostConstruct
    public void init() {
        this.parameterJpaRepository = new JpaRepositoryImpl<>(ParameterInfo.class, entityManager);
        this.equipmentManageJpaRepository = new JpaRepositoryImpl<>(EquipmentManage.class, entityManager);
        this.diagnoseResultInfoJpaRepository = new JpaRepositoryImpl<>(DiagnoseResultInfo.class, entityManager);
        this.diagnoseBatchJpaRepository = new JpaRepositoryImpl<>(DiagnoseResultBatch.class, entityManager);
        this.dataBatchJpaRepository = new JpaRepositoryImpl<>(EsmsDataBatch.class, entityManager);
    }

    public JSONArray type1Read(JSONObject data) {
        return readDiagnose(data, key -> "soc".equals(key) || "dcbrl".equals(key) || "kccdl".equals(key) || "xhcs".equals(key)
                || key.startsWith("dtsoc_") || key.startsWith("dtzz_") || key.startsWith("dtrl_"));
    }

    public void type1Write(JSONObject data) {
        List<String> keys = Arrays.asList("soc", "kcxdl", "kccdl", "xhcs", "dczlsd", "socbzc",
                "socfc", "socqwz", "socbyxs", "socsfwsql", "socsfwsqm", "socsfwsqu",
                "socsfwsc", "socyzx", "dtrlbzc", "dtrlfc", "dtrlqwz", "dtrlbyxs", "dtrlsfwsql",
                "dtrlsfwsqm", "dtrlsfwsqu", "dtrlsfwsc", "dtrlyzx", "dtsocbzc", "dtsocfc", "dtsocqwz",
                "dtsocbyxs", "dtsocsfwsql", "dtsocsfwsqm", "dtsocsfwsqu", "dtsocsfwsc", "dtsocyzx", "dtzzbzc",
                "dtzzfc", "dtzzqwz", "dtzzbyxs", "dtzzsfwsql", "dtzzsfwsqm", "dtzzsfwsqu", "dtzzsfwsc", "dtzzyzx",
                "dtdybzc", "dtdyfc", "dtdyqwz", "dtdybyxs", "dtdysfwsql", "dtdysfwsqm", "dtdysfwsqu", "dtdysfwsc",
                "dtdyyzx", "dlbzc", "dlfc", "dlqwz", "dlbyxs", "dlsfwsql", "dlsfwsqm", "dlsfwsqu", "dlsfwsc", "dlyzx", "wdbzc",
                "wdfc", "wdqwz", "wdbyxs", "wdsfwsql", "wdsfwsqm", "wdsfwsqu", "wdsfwsc", "wdyzx");
        saveDiagnoseResultInfo(1, data, keys::contains);
    }

    public JSONArray type2Read(JSONObject data) {
        return this.readEsmsData(data, key -> key.equals("BatCurrent") || (key.startsWith("Cell_") && key.endsWith("_Volt")) ||
                (key.startsWith("Cell_") || key.endsWith("_Temp")));
    }

    public void type2Write(JSONObject data) {
        saveDiagnoseResultInfo(2, data, key -> key.startsWith("wdad_") || key.equals("dlad")
                || key.startsWith("dtsoc_") || key.startsWith("dtzzad_") || key.startsWith("dtrlad_"));
    }

    public JSONArray type3Read(JSONObject data) {
        return this.readDiagnose(data, key -> key.startsWith("dtzzad_")
                || key.startsWith("wdad_")
                || key.startsWith("dtrlad_")
                || key.equals("dlad"));
    }

    public void type3Write(JSONObject data) {
        saveDiagnoseResultInfo(3, data, key -> key.startsWith("dtzz_") || key.startsWith("dtrl_"));
    }

    public JSONArray type4Read(JSONObject data) {
        return this.readEsmsData(data, key -> (key.startsWith("Cell_") && key.endsWith("_Volt")) || key.equals("BatCurrent"));
    }

    public void type4Write(JSONObject data) {
        saveDiagnoseResultInfo(4, data, key -> key.equals("dcbrl"));
    }

    public void type5Write(JSONObject data) {
        saveDiagnoseResultInfo(5, data, key -> key.equals("zdyxcddl") || key.equals("cddlqqz")
                || key.equals("stfddl") || key.equals("stcddl") || key.equals("wtfddl") || key.equals("wtcddl"));
    }

    public JSONArray type5Read(JSONObject data) {
        return this.readEsmsData(data, key -> key.equals("MaxAllwChrgCurr")
                || key.equals("ChrgReqCurr") || key.equals("DSCH_OCT") || key.equals("CHRG_OCT")
                || key.equals("DSCH_OCS") || key.equals("CHRG_OCS"));
    }

    protected JSONArray readEsmsData(JSONObject data, MatchFunction func) {
        JSONArray r = new JSONArray();
        String ip = data.getString("ip");
        String macid = data.getString("macid");
        Long cycle = data.getLong("cycle");
        Long time = data.getLong("time");

        r.addAll(elasticsearchService.searchByMatchFunction(QueryBuilders.boolQuery()
                .filter(QueryBuilders.termQuery("ip", ip))
                .filter(QueryBuilders.termQuery("macid", macid))
                .filter(QueryBuilders.rangeQuery("time").gte(time - cycle).lte(time)), func));
        return r;

    }

    protected JSONArray readDiagnose(JSONObject data, MatchFunction func) {
        JSONArray r = new JSONArray();
        String ip = data.getString("ip");
        String port = data.getString("port");
        String macid = data.getString("macid");
        long time = data.getLong("time");
        long cycle = data.getLong("cycle");

        //获取最新一次的数据
        QDiagnoseResultBatch qBatch = QDiagnoseResultBatch.diagnoseResultBatch;
        BooleanExpression where = qBatch.ip.eq(ip)
                .and(qBatch.macId.eq(macid))
                .and(qBatch.time.goe(time - cycle));
        List<DiagnoseResultBatch> batches = diagnoseBatchJpaRepository.findAll(where);
        if (batches.isEmpty()) {
            return r;
        }
        //按日期索引
        Map<Long, JSONObject> map = new HashMap<>();
        for (DiagnoseResultBatch batch : batches) {
            JSONObject jsonObject = map.get(batch.getTime());
            if (jsonObject == null) {
                jsonObject = new JSONObject();
                jsonObject.put("time", batch.getTime());
                jsonObject.put("ip", batch.getIp());
                jsonObject.put("port", batch.getPort());
                jsonObject.put("macid", batch.getMacId());
            }
            List<DiagnoseResultInfo> list = diagnoseResultInfoJpaRepository
                    .findAll(QDiagnoseResultInfo.diagnoseResultInfo.batch.id.eq(batch.getId()));
            for (DiagnoseResultInfo info : list) {
                String key = info.getSetVal();
                if (func.isMatch(key)) {
                    jsonObject.put(key, Double.parseDouble(info.getResultVal()));
                }
            }
            map.put(batch.getTime(), jsonObject);
        }
        for (Map.Entry<Long, JSONObject> entry : map.entrySet()) {
            r.add(entry.getValue());
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("return {}", r);
        }
        return r;
    }

    protected void saveDiagnoseResultInfo(Integer type, JSONObject data, MatchFunction func) {
        Long time = data.getLong("time");
        String ip = data.getString("ip");
        String port = data.getString("port");
        String macid = data.getString("macid");

        Set<String> keys = data.keySet();
        keys.remove("ip");
        keys.remove("port");
        keys.remove("macid");
        keys.remove("time");
        keys.remove("cycle");

        DiagnoseResultBatch batch = new DiagnoseResultBatch();
        batch.setIp(ip);
        batch.setTime(time);
        batch.setPort(port);
        batch.setMacId(macid);
        batch.setTypeId(type);
        diagnoseBatchJpaRepository.save(batch);
        Integer infoType = (type == 2 || type == 3) ? ParameterInfo.OBJECT_NAME_BATTERY : ParameterInfo.OBJECT_NAME_BATTERY_PACK;
        EquipmentManage equipmentManage = null;
        if (infoType.equals(ParameterInfo.OBJECT_NAME_BATTERY)) {
            //电池单体
            Optional<String> first = keys.stream().filter(key -> key.contains("_")).findFirst();
            if (first.isPresent()) {
                String code = String.format("%s#Cell_%s_", macid, first.get().split("_")[1]);
                equipmentManage = equipmentManageJpaRepository.findOne(QEquipmentManage.equipmentManage.code.eq(code));
            }
        }
        if (infoType.equals(ParameterInfo.OBJECT_NAME_BATTERY_PACK)) {
            equipmentManage = equipmentManageJpaRepository.findOne(QEquipmentManage.equipmentManage.code.eq(macid));
        }
        if (equipmentManage == null) {
            LOG.warn("equipmentManage 为空");
        }

        for (String key : keys) {
            if (func.isMatch(key)) {
                String value = data.get(key).toString();
                DiagnoseResultInfo diagnoseResultInfo = new DiagnoseResultInfo();
                diagnoseResultInfo.setEquipment(equipmentManage);
                diagnoseResultInfo.setCreateTime(new Date());
                diagnoseResultInfo.setIsValid(1L);
                diagnoseResultInfo.setResultVal(value);
                diagnoseResultInfo.setSetVal(key);
                diagnoseResultInfo.setBatch(batch);
                diagnoseResultInfoJpaRepository.save(diagnoseResultInfo);
            } else {
                LOG.warn("未识别的字段 {}", key);
            }
        }
    }

    protected List<EsmsDataBatch> getBatchIds(Long time, Long cycle) {
        QEsmsDataBatch qBatch = QEsmsDataBatch.esmsDataBatch;
        return dataBatchJpaRepository.findAll(qBatch.time.between(time - cycle, time));
    }

}
